package com.ketti.team;

import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.BitmapFactory;
import android.text.InputType;
import android.text.Selection;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewStub;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.Toast;
import android.widget.CompoundButton.OnCheckedChangeListener;

public class SourceView extends RelativeLayout {
	
	public int tabNumber;
	private int mIndicatorLocation;
	
	private final int TOAST_Y_POSITION = 200;
	private final String PATH = "/sdcard/source/";
	private NewEditText mNewEditText;
	
	private Context mContext;
	
	private View 		mSearchBox;
	private Button 		mSearchBoxButton;
	private EditText 	mSearchBoxEdit;
	private CheckBox 	mSearchBoxCheck;
	private ImageView 	mSearchIndicator;
	
	private View 		mTabMenu;
	private Button 		mTabMenuNewButton;
	private Button 		mTabMenuOpenButton;
	private Button 		mTabMenuSaveButton;
	private Button 		mTabMenuCloseButton;	
	private ImageView 	mTabMenuIndicator;
	private int 		mMenuIndicatorSize;
		
	private int 		mPreSearchStart = 0;
	private int 		mPreSearchCount = 0;
	private String 		mPreSearchString = "";	
	private String 		mFileName;
	
	private InputMethodManager inputMethodManager;
	
	private Animation mPushTopIn;	
	
	private OnClickListener tabMenuOpenClickListener;
	private OnClickListener tabMenuCloseClickListener;
	
	/**
	 * @Method			: setTabMenuOpenClickListener
	 * @Date			: 2010. 5. 22. 
	 * @Author			: chitacan
	 * @Description		: setter for tabMenuOpenClickListener
	 * @param onClickListener
	 **/
	public void setTabMenuOpenClickListener(OnClickListener onClickListener){
		tabMenuOpenClickListener = onClickListener;
	}
	
	/**
	 * @Method			: setTabMenuCloseClickListener
	 * @Date			: 2010. 5. 22. 
	 * @Author			: chitacan
	 * @Description		: setter for setTabMenuCloseClickListener
	 * @param onClickListener
	 **/
	public void setTabMenuCloseClickListener(OnClickListener onClickListener){
		tabMenuCloseClickListener = onClickListener;
	}
	
	/**
	 * @Method			: setContext
	 * @Date			: 2010. 5. 22. 
	 * @Author			: chitacan
	 * @Description		: setter for mContext
	 * @param context
	 **/
	public void setContext(Context context){
		mContext = context;
	}
	
	/**
	 * @Method			: getNewSouceView
	 * @Date			: 2010. 5. 22. 
	 * @Author			: chitacan
	 * @Description		: getter for mNewEditText
	 * @return			: NewEditText included in this class
	 **/
	public NewEditText getNewSouceView(){
		return mNewEditText;
	}

	public SourceView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
	}

	public SourceView(Context context, AttributeSet attrs) {
		super(context, attrs);
	}

	public SourceView(Context context) {
		super(context);
		String inflaterService = Context.LAYOUT_INFLATER_SERVICE;
		LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(inflaterService);
		layoutInflater.inflate(R.layout.source_view, this, true);		
		
		mNewEditText 	= (NewEditText) 	findViewById(R.id.source_editor);
		mNewEditText.setSourceView(this);
				
		mNewEditText.setGravity(Gravity.TOP);
		mNewEditText.setHorizontallyScrolling(true);	
		mPushTopIn = AnimationUtils.loadAnimation(getContext(), R.anim.push_top_in);
		mMenuIndicatorSize = BitmapFactory.decodeResource(getResources(), R.drawable.triangle).getWidth();
	}
	
	/**
	 * @Method			: setFileName
	 * @Date			: 2010. 5. 22. 
	 * @Author			: chitacan
	 * @Description		: setter for mFileName
	 * @param filename
	 **/
	public void setFileName(String filename){
		mFileName = filename;
	}
	
	/**
	 * @Method			: setSource
	 * @Date			: 2010. 5. 22. 
	 * @Author			: chitacan
	 * @Description		: read file from SD card with FileIO class.
	 **/
	public void setSource(){
		if(mFileName != null){
			FileIO fileio = new FileIO();
			mNewEditText.setText(fileio.readFile(PATH, mFileName));
		}
	}	
	
	/**
	 * @Method			: controlSearchBox
	 * @Date			: 2010. 5. 22. 
	 * @Author			: chitacan
	 * @Description		: controller for toggle searchBox on/off. 
	 * 					  if mSearchBox is null, find its xml and inflate it.
	 **/
	public void controlSearchBox(){
		if(mSearchBox == null){			
    		mSearchBox = ((ViewStub) findViewById(R.id.search_box_layout)).inflate();      		
    		findSearchBoxComponentAndHookUp();
    		}			

		if(mTabMenu != null && mTabMenu.getVisibility() == View.VISIBLE)
			mTabMenu.setVisibility(View.GONE);
		mSearchBox.setVisibility(mSearchBox.getVisibility() == View.VISIBLE ? View.GONE : View.VISIBLE);
		if(mSearchBox.getVisibility() == View.VISIBLE)
			mSearchBox.startAnimation(mPushTopIn);
		
		relocateSearchMenuIndicator();
	}
	
	/**
	 * @Method			: relocateSearchMenuIndicator
	 * @Date			: 2010. 5. 22. 
	 * @Author			: chitacan
	 * @Description		: calculate indicator's location and relocate it
	 **/
	public void relocateSearchMenuIndicator(){
		mIndicatorLocation = (getMeasuredWidth()/((EditorActivity.sTabCount+1)*2))*(tabNumber*2 + 1);
		mSearchIndicator.setPadding(mIndicatorLocation - (mMenuIndicatorSize/2), getPaddingTop(), getPaddingRight(), getPaddingBottom());
	}
	
	/**
	 * @Method			: controlTabMenu
	 * @Date			: 2010. 5. 22. 
	 * @Author			: chitacan
	 * @Description		: controller for toggle TabMenu on/off. 
	 * 					  if mSearchBox is null, find its xml and inflate it.
	 **/
	public void controlTabMenu(){
		if(mTabMenu == null){
			mTabMenu = ((ViewStub) findViewById(R.id.tab_menu_layout)).inflate();			
    		findTabMenuComponentAndHookUp();
			}		
		
		if(mSearchBox != null && mSearchBox.getVisibility() == View.VISIBLE)
			mSearchBox.setVisibility(View.GONE);
		mTabMenu.setVisibility(mTabMenu.getVisibility() == View.VISIBLE ? View.GONE : View.VISIBLE);
		if(mTabMenu.getVisibility() == View.VISIBLE)
			mTabMenu.startAnimation(mPushTopIn);
		relocateTabMenuIndicator();
	}
	
	/**
	 * @Method			: relocateTabMenuIndicator
	 * @Date			: 2010. 5. 22. 
	 * @Author			: chitacan
	 * @Description		: calculate indicator's location and relocate it
	 **/
	public void relocateTabMenuIndicator(){
		mIndicatorLocation = (getMeasuredWidth()/((EditorActivity.sTabCount+1)*2))*(tabNumber*2 + 1);
		mTabMenuIndicator.setPadding(mIndicatorLocation - (mMenuIndicatorSize/2), getPaddingTop(), getPaddingRight(), getPaddingBottom());
	}
	
	/**
	 * @Method			: findTabMenuCompoentAndHookUp
	 * @Date			: 2010. 5. 22. 
	 * @Author			: chitacan
	 * @Description		: if TabMenu has just been inflated, find some components and initialize it
	 **/
	public void findTabMenuComponentAndHookUp(){
		mTabMenuNewButton 	= (Button) findViewById(R.id.tabmenu_box_new);
		mTabMenuOpenButton	= (Button) findViewById(R.id.tabmenu_box_open);
		mTabMenuSaveButton	= (Button) findViewById(R.id.tabmenu_box_save);
		mTabMenuCloseButton	= (Button) findViewById(R.id.tabmenu_box_close);
		mTabMenuIndicator 	= (ImageView)findViewById(R.id.tabmenu_tri_indicator);					
		
		mTabMenuNewButton.setTextSize(Setting.getmFontSize());
		mTabMenuOpenButton.setTextSize(Setting.getmFontSize());
		mTabMenuSaveButton.setTextSize(Setting.getmFontSize());
		mTabMenuCloseButton.setTextSize(Setting.getmFontSize());				
		
		mTabMenuCloseButton.setOnClickListener(tabMenuCloseClickListener);
		
		mTabMenuOpenButton.setOnClickListener(tabMenuOpenClickListener);
		
	}

	/**
	 * @Method			: findSearchBoxComponentAndHookUp
	 * @Date			: 2010. 5. 22. 
	 * @Author			: chitacan
	 * @Description		: if searchBox has just been inflated, find some components and initialize it
	 **/
	public void findSearchBoxComponentAndHookUp() {
		
		mSearchBoxButton = (Button) 			findViewById(R.id.search_box_button);
		mSearchBoxEdit	= (EditText)		findViewById(R.id.search_box_edit);
		mSearchBoxCheck	= (CheckBox)		findViewById(R.id.search_box_check);
		mSearchIndicator = (ImageView)		findViewById(R.id.search_tri_indicator);
		
		mSearchBoxButton.setTextSize(Setting.getmFontSize());
		mSearchBoxEdit.setTextSize(Setting.getmFontSize());	
		
		
		mSearchBoxButton.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {	
				
				// if there's no string in searchBoxEdit, toast a message
				if(mSearchBoxEdit.length() == 0){
					if(!(mSearchBoxCheck.isChecked())){
						Toast toast = Toast.makeText(getContext(), "Please enter some text to search", Toast.LENGTH_SHORT);
						toast.setGravity(Gravity.TOP, 0, TOAST_Y_POSITION);
						toast.show();
					}
					else{
						Toast toast = Toast.makeText(getContext(), "Please enter some number to go line", Toast.LENGTH_SHORT);
						toast.setGravity(Gravity.TOP, 0, TOAST_Y_POSITION);
						toast.show();
					}				
				}
				else{
					if(!(mSearchBoxCheck.isChecked()))
						searchWithString();				
					else
						searchWithLineNumber();
				}															
			}
		});
		
		mSearchBoxCheck.setOnCheckedChangeListener(new OnCheckedChangeListener() {
			
			@Override
			public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
				if(isChecked == true){
					mSearchBoxButton.setText("Line");
					mSearchBoxEdit.setHint("Type to Go Line");
					mSearchBoxEdit.setText("");
					mSearchBoxEdit.setInputType(InputType.TYPE_CLASS_PHONE);
				}					
				else{
					mSearchBoxButton.setText("Search");
					mSearchBoxEdit.setHint("Type to Search");
					mSearchBoxEdit.setText("");
					mSearchBoxEdit.setInputType(InputType.TYPE_CLASS_TEXT);
				}					
			}
		});		
	}	
	
	
	/**
	 * @Method			: searchWithString
	 * @Date			: 2010. 5. 22. 
	 * @Author			: chitacan
	 * @Description		: get edittext's string in searchBox and do 'search' action in current source.
	 **/
	private void searchWithString(){
		
		// we can't expect when user edit the source in newSourceView, therefore we have to
		// bring the source whenever search button being clicked
		String searchBoxEditString = mSearchBoxEdit.getText().toString();
		String newSourceViewString = mNewEditText.getText().toString();
		
		// if the searchBoxEdit's string is different from previous result, start from beginning of source					
		if(!(searchBoxEditString.equals(mPreSearchString))){
			mPreSearchString	= searchBoxEditString;
			mPreSearchStart	= newSourceViewString.indexOf(mPreSearchString);
			mPreSearchCount	= mPreSearchString.length();												
			
			// if there's a match, select it										
			if(mPreSearchStart != -1)
				Selection.setSelection(mNewEditText.getText(), mPreSearchStart, mPreSearchStart + mPreSearchCount);
			
			// no match, show a toast message
			else{
				mPreSearchString	= "";
				Toast toast = Toast.makeText(getContext(), "No matches", Toast.LENGTH_SHORT);
				toast.setGravity(Gravity.TOP, 0, TOAST_Y_POSITION);
				toast.show();							
			}
		
		// if the searchBoxEdit's string is same as previous result, starts at next to the previous result
		}else {
			mPreSearchStart = newSourceViewString.indexOf(mPreSearchString, mPreSearchStart + mPreSearchCount);
			
			// if there's no matches, start again
			if(mPreSearchStart == -1)
				mPreSearchStart = newSourceViewString.indexOf(mPreSearchString);
			
			Selection.setSelection(mNewEditText.getText(), mPreSearchStart , mPreSearchStart  + mPreSearchCount);						
		}					
		mNewEditText.requestFocus();
	}
	
	
	/**
	 * @Method			: searchWithLineNumber
	 * @Date			: 2010. 5. 22. 
	 * @Author			: chitacan
	 * @Description		: get edittext's string in searchBox(number) and do 'go line' action in current source
	 **/
	private void searchWithLineNumber(){
		String searchBoxEditString = mSearchBoxEdit.getText().toString();
		
		if(TextUtils.isDigitsOnly(mSearchBoxEdit.getText())){
			int desireLine = Integer.valueOf(searchBoxEditString) - 1;
			if(desireLine < mNewEditText.getLayout().getLineCount() && desireLine > -1){							
				Selection.setSelection(mNewEditText.getText(), mNewEditText.getLayout().getLineStart(desireLine) , mNewEditText.getLayout().getLineStart(desireLine));
				Selection.moveToLeftEdge(mNewEditText.getText(), mNewEditText.getLayout());
				mNewEditText.requestFocus();
			}else{
				Toast toast = Toast.makeText(getContext(), "Line number out of range", Toast.LENGTH_SHORT);
				toast.setGravity(Gravity.TOP, 0, TOAST_Y_POSITION);
				toast.show();							
			}
		}
	}
	
	/**
	 * @Method			: setInputMethodManager
	 * @Date			: 2010. 5. 22. 
	 * @Author			: chitacan
	 * @Description		: setter for InputMethodManager
	 * @param imm
	 **/
	public void setInputMethodManager(InputMethodManager imm){
		inputMethodManager = imm;
	}		
}
